<script setup lang="ts">
import { ref, onBeforeMount, computed, nextTick } from 'vue';
import {
  reqGetSpuInfo,
  reqGetAllTrademark,
  reqGetBaseSaleAttrList,
  reqGetSpuSaleAttrList,
  reqSaveSpuInfo
} from '@/api/product/spu.ts';
import { reqImgUpload } from '@/api/upload.ts';
import { quasarFormStyle } from '@/setting.ts';
import type {
  SpuInfo,
  Trademark,
  BaseSaleAttr,
  SpuSaleAttr,
  SpuImage,
  SpuSaleAttrValue
} from '@/api/product/type.ts';
import { QFile, useQuasar, QInput } from 'quasar';
import type { QRejectedEntry, QTableColumn } from 'quasar';
import { useCompRef } from '@/utils/useCompRef';
import MyQTable from '@/components/MyQTable.vue';

const { notify } = useQuasar();
// 定义props 接收spuId
const props = defineProps<{
  spuId: number | undefined;
  category3Id: number;
}>();
// 表单数据
const spuForm = ref<SpuInfo>({
  category3Id: 0,
  description: '',
  spuName: '',
  tmId: null,
  spuImageList: [] as SpuImage[],
  spuSaleAttrList: [] as SpuSaleAttr[]
});
// 获取SpuInfo
async function getSpuInfo() {
  if (!props.spuId) {
    spuForm.value = {
      category3Id: props.category3Id,
      description: '',
      spuName: '',
      tmId: null,
      spuImageList: [] as SpuImage[],
      spuSaleAttrList: [] as SpuSaleAttr[]
    };
    return;
  }
  try {
    const result = await reqGetSpuInfo(props.spuId);
    if (result.code === 200) {
      spuForm.value = result.data;
    } else {
      throw new Error('spu详情获取失败');
    }
  } catch (error: any) {
    notify({
      type: 'negative',
      message: error.message,
      position: 'top'
    });
  }
}
// 品牌列表
const trademarkList = ref<Trademark[]>();
// 获取可选品牌列表
async function getAllTrademark() {
  try {
    const result = await reqGetAllTrademark();
    if (result.code === 200) {
      trademarkList.value = result.data;
    } else {
      throw new Error('品牌列表获取失败');
    }
  } catch (error: any) {
    notify({
      type: 'negative',
      message: error.message,
      position: 'top'
    });
  }
}
// 图片列表
const imgFiles = ref<File[]>([]);
const files = useCompRef(QFile);
// 图片过滤器
const filesFiler = (files: File[]) => {
  // jpg png图片 最大1mb
  return files.filter(
    file => /^image\/(jpeg|png)$/.test(file.type) && file.size < 1024 * 1024 * 1
  );
};
// 图片不符合要求
function filesRejected(rejectedEntries: QRejectedEntry[]) {
  notify({
    type: 'negative',
    message: `${rejectedEntries.length}张图片格式或大小不符合要求`,
    position: 'top'
  });
}
// 处理图片列表
function handleImgFiles(files: File[]) {
  const previewAndUploadImg = async (file: File, imgObj: SpuImage) => {
    const reader = new FileReader();
    // 预览图片并上传到服务器
    reader.readAsDataURL(file);
    reader.onload = () => {
      const imgUrl = reader.result as string;
      imgObj.imgUrl = imgUrl;
    };
    // 上传
    try {
      const formData = new FormData();
      formData.append('file', file);
      const result = await reqImgUpload(formData);
      if (result.code === 200) {
        imgObj.imgUrl = result.data;
        return Promise.resolve('ok');
      } else {
        throw new Error('图片上传失败');
      }
    } catch (error: any) {
      notify({
        type: 'negative',
        message: error.message,
        position: 'top'
      });
      // 删除上传失败的图片对象
      const index = spuForm.value.spuImageList.findIndex(
        item => item === imgObj
      );
      spuForm.value.spuImageList.splice(index, 1);
      return Promise.resolve('ok');
    }
  };
  // 向spuForm中的spuImageList添加数据
  const promises = files.map(item => {
    spuForm.value.spuImageList.push({
      imgName: item.name,
      imgUrl: '',
      spuId: props.spuId
    });
    return previewAndUploadImg(
      item,
      spuForm.value.spuImageList[spuForm.value.spuImageList.length - 1]
    );
  });
  Promise.all(promises).then(() => (imgFiles.value = []));
}

// 基础销售属性
const baseSaleAttrList = ref<BaseSaleAttr[]>();
// 获取基础销售属性列表
async function getBaseSaleAttrList() {
  try {
    const result = await reqGetBaseSaleAttrList();
    if (result.code === 200) {
      baseSaleAttrList.value = result.data;
    } else {
      throw new Error('基础销售属性列表获取失败');
    }
  } catch (error: any) {
    notify({
      type: 'negative',
      message: error.message,
      position: 'top'
    });
  }
}
// spu销售属性列表
const spuSaleAttrList = ref<SpuSaleAttr[]>([]);
// 获取spu销售属性列表
async function getSpuSaleAttrList() {
  if (!props.spuId) return;
  try {
    const result = await reqGetSpuSaleAttrList(props.spuId);
    if (result.code === 200) {
      spuSaleAttrList.value = result.data;
    } else {
      throw new Error('spu销售属性列表获取失败');
    }
  } catch (error: any) {
    notify({
      type: 'negative',
      message: error.message,
      position: 'top'
    });
  }
}
// 可选的销售属性列表
// 从baseSaleAttrList中过滤掉spuSaleAttrList
const saleAttrListChoice = computed(() => {
  const baseList = baseSaleAttrList.value || [];
  const spuList = spuSaleAttrList.value || [];
  return baseList.filter(
    item => !spuList.some(spuItem => spuItem.baseSaleAttrId === item.id)
  );
});
// 选中的销售属性id
const checkedAtrrId = ref<number>();
// 添加spu销售属性
function addSpuSaleAttr() {
  const baseSaleAttr = baseSaleAttrList.value?.find(
    item => item.id === checkedAtrrId.value
  );
  spuSaleAttrList.value.push({
    baseSaleAttrId: checkedAtrrId.value!,
    saleAttrName: baseSaleAttr!.name,
    spuId: props.spuId,
    spuSaleAttrValueList: []
  });
  checkedAtrrId.value = undefined;
}
// columns
const columns: QTableColumn[] = [
  {
    name: 'index',
    label: '序号',
    field: '',
    align: 'center',
    style: 'width: 80px'
  },
  {
    name: 'sale-attr-name',
    label: '销售属性名称',
    field: 'saleAttrName',
    align: 'left'
  },
  { name: 'value-list', label: '销售属性值', field: '', align: 'left' },
  { name: 'control', label: '操作', field: 'id', align: 'left' }
];
// qInput组件
const qInputSale = ref<InstanceType<typeof QInput>[]>();
interface EditSpuSaleAttrValue extends SpuSaleAttrValue {
  isEdit?: boolean;
}
// 添加spu销售属性值
function addSpuSaleAttrValue(row: SpuSaleAttr) {
  row.spuSaleAttrValueList.push({
    saleAttrValueName: '',
    spuId: props.spuId,
    baseSaleAttrId: row.baseSaleAttrId,
    saleAttrName: row.saleAttrName,
    isEdit: true
  } as EditSpuSaleAttrValue);
  // 聚焦表单组件
  nextTick(() => {
    qInputSale.value![0].focus();
  });
}
// 表单组件失焦
function inputBlur(spuSaleAttrValueList: SpuSaleAttrValue[], index: number) {
  const item = spuSaleAttrValueList[index] as EditSpuSaleAttrValue;
  if (item.saleAttrValueName.trim()) {
    delete item.isEdit;
  } else {
    spuSaleAttrValueList.splice(index, 1);
  }
}
async function save() {
  spuForm.value.spuSaleAttrList = spuSaleAttrList.value;
  try {
    const result = await reqSaveSpuInfo(spuForm.value);
    if (result.code === 200) {
      notify({
        type: 'positive',
        message: 'SPU信息提交成功',
        position: 'top'
      });
      $emit('hideSpuForm', 'ok');
    } else {
      throw new Error('SPU信息提交失败');
    }
  } catch (error: any) {
    notify({
      type: 'negative',
      message: error.message,
      position: 'top'
    });
  }
}
const $emit = defineEmits<{
  hideSpuForm: [flag?: string];
}>();
onBeforeMount(() => {
  getAllTrademark();
  getBaseSaleAttrList();
  getSpuSaleAttrList();
  getSpuInfo();
});
</script>

<template>
  <q-card class="q-mt-md">
    <q-card-section>
      <q-input
        label="SPU名称"
        v-bind="quasarFormStyle"
        v-model="spuForm.spuName"
        dense
      ></q-input>
      <q-select
        label="SPU品牌"
        v-bind="quasarFormStyle"
        style="width: 180px"
        class="q-my-md"
        v-model="spuForm.tmId"
        :options="trademarkList"
        option-value="id"
        emit-value
        option-label="tmName"
        map-options
        dense
        options-dense
      ></q-select>
      <q-input
        label="SPU描述"
        v-bind="quasarFormStyle"
        type="textarea"
        v-model="spuForm!.description"
        input-style="height: 80px;"
        dense
      ></q-input>
      <q-field
        label="SPU图片"
        dense
        borderless
        readonly
        class="q-my-xs"
      ></q-field>
      <!-- 图片列表和上传图片 -->
      <div class="img_list flex flex-wrap q-gutter-md q-pl-md">
        <div
          class="item relative-position"
          v-for="(item, i) in spuForm.spuImageList"
          :key="item.id"
        >
          <q-img class="absolute-full" :src="item.imgUrl" :alt="item.imgName" />
          <!-- 蒙层 删除按钮 -->
          <div class="mask absolute-full">
            <q-icon
              class="icon absolute-center"
              size="sm"
              name="delete"
              color="white"
              @click="spuForm.spuImageList.splice(i, 1)"
            ></q-icon>
          </div>
        </div>
        <div
          class="item relative-position bg-grey-3"
          @click="files!.pickFiles()"
        >
          <q-icon class="absolute-center" color="grey-6" name="add" size="lg" />
          <q-file
            class="hidden"
            multiple
            ref="files"
            v-model="imgFiles"
            @update:model-value="handleImgFiles"
            :filter="filesFiler as unknown as QFile['filter']"
            @rejected="filesRejected"
          />
        </div>
      </div>
      <q-field
        label="SPU销售属性"
        dense
        borderless
        readonly
        class="q-my-xs"
      ></q-field>
      <div class="q-pl-md">
        <div class="flex justify-left items-center">
          <q-select
            v-bind="quasarFormStyle"
            style="width: 180px"
            class="q-mr-md"
            :label="`还未选择${saleAttrListChoice.length}个`"
            v-model="checkedAtrrId"
            :options="saleAttrListChoice"
            option-value="id"
            emit-value
            option-label="name"
            map-options
            dense
            :readonly="saleAttrListChoice.length === 0"
          ></q-select>
          <q-btn
            label="添加属性"
            icon="add"
            color="primary"
            :disabled="!checkedAtrrId"
            @click="addSpuSaleAttr"
          ></q-btn>
        </div>
        <my-q-table class="q-mt-md" :data="spuSaleAttrList" :columns="columns">
          <template #body-cell-value-list="{ row }">
            <q-td>
              <q-chip
                v-for="(item, i) in row.spuSaleAttrValueList"
                :key="item.id"
                removable
                color="primary"
                outline
                @remove="row.spuSaleAttrValueList.splice(i, 1)"
              >
                <template v-if="!item.isEdit">
                  {{ item.saleAttrValueName }}
                </template>
                <q-input
                  ref="qInputSale"
                  v-model.trim="item.saleAttrValueName"
                  @blur="() => inputBlur(row.spuSaleAttrValueList, i)"
                  @keyup.enter="() => inputBlur(row.spuSaleAttrValueList, i)"
                  style="width: 40px"
                  v-else
                ></q-input>
              </q-chip>
              <q-btn
                class="q-ml-xs"
                size="xs"
                round
                color="positive"
                icon="add"
                @click="addSpuSaleAttrValue(row)"
              ></q-btn>
            </q-td>
          </template>
          <template #body-cell-control="{ pageIndex }">
            <q-td>
              <q-btn
                icon="delete"
                color="negative"
                size="xs"
                @click="spuSaleAttrList.splice(pageIndex, 1)"
              ></q-btn>
            </q-td>
          </template>
          <!-- 覆盖设定好的no-data样式 -->
          <template #no-data>
            <div class="full-width row flex-center q-py-lg">暂无数据</div>
          </template>
        </my-q-table>
      </div>
      <div class="q-mt-sm q-gutter-sm">
        <q-btn color="primary" label="保存" @click="save"></q-btn>
        <q-btn
          color="primary"
          flat
          label="取消"
          @click="$emit('hideSpuForm')"
        ></q-btn>
      </div>
    </q-card-section>
  </q-card>
</template>

<style scoped lang="scss">
.img_list {
  .item {
    width: 150px;
    height: 150px;
    border: 1px solid #ccc;

    .mask {
      background-color: rgba(0, 0, 0, 0.5);
      opacity: 0;
      transition: all 0.5s;
    }

    &:hover {
      .mask {
        opacity: 1;
      }
    }

    .upload {
      height: 100%;

      :deep(.q-field__control) {
        height: 100%;
      }
    }
  }
}
</style>
